<?php

namespace catchAdmin\propaganda\service;

use MongoDB\BSON\ObjectId;
use catcher\exceptions\FailedException;
use app\common\model\PropagandaEducation as EDModel;
use app\common\model\PropagandaEducationHistory as PEHModel;

class DataAnalysisService
{
    /**
     * 数据概况
     * @param int $department_id 科室id
     * @param array $pushTime 推送时间 [起-止]
     * @return array
     */
    public function getDataProfiling(int $department_id=0, array $pushTime=[]): array
    {
        //定义查询条件
        $where = [];
        if ($department_id !== 0) {
            $where[] = ['department_id', '=', $department_id];
        }

        //查询条件匹配的宣教记录id
        $history_id = (new PEHModel())->where($where)->column('id');

        //将宣教记录id转换ObjectId类型
        $history_ids = array_map(function ($v) { return new ObjectId($v); }, $history_id);

        #阅读人数
        $readPeopleNum = $this->calculateEdPeople(1, $history_ids, $pushTime);

        #推送人数
        $pushPeopleNum = $this->calculateEdPeople(2, $history_ids, $pushTime);

        #阅读量
        $readVolumeWhere = $where;
        //已读条件
        $readVolumeWhere[] = ['isview', '=', 1];
        $readVolume = $this->calculateEdMeasure($readVolumeWhere, 'read_ymd', $pushTime);

        #推送量
        $pushVolume = $this->calculateEdMeasure($where, 'pushtime_ymd', $pushTime);

        #推送课程数
        $pushCourse = $this->calculateEdPushCourse($history_ids, $pushTime);

        #课程数
        $edCourse = $this->calculateEdCourse($where, $pushTime);

        return  [
            'totalReadPeopleNum' => $readPeopleNum['totalNum'],//总阅读人数
            'newReadPeopleNum'  => $readPeopleNum['newNum'],//新增阅读人数
            'totalReadingVolume' => $readVolume['totalNum'],//总阅读量
            'newReadingVolume'   => $readVolume['newNum'],//新增阅读量
            'totalPushPeopleNum' => $pushPeopleNum['totalNum'],//总推送人数
            'newPushPeopleNum'   => $pushPeopleNum['newNum'],//新增推送人数
            'totalPushVolume'    => $pushVolume['totalNum'],//总推送量
            'newPushVolume'      => $pushVolume['newNum'],//新增推送量
            'totalPushCourseNum' => $pushCourse['totalNum'],//总推送课程数
            'newPushCourseNum'   => $pushCourse['newNum'],//新增推送课程数
            'totalEdCourseNum'   => $edCourse['totalNum'],//总课程数
            'newEdCourseNum'     => $edCourse['newNum']//新增课程数
        ];
    }

    /**
     * 聚合宣教人数
     * @param int $type 类型 1阅读人数，2推送人数
     * @param array $history_ids 宣教记录id
     * @param string $ymd 时间
     * @return int
     */
    private function aggregationEvangelist(int $type, array $history_ids, string $ymd): int
    {
        if (empty($ymd)) {
            throw new FailedException('请传入时间参数');
        }
        $match['_id'] = ['$in' => $history_ids];
        $match['deleted_at'] = 0;

        //按类型判断条件
        if ($type == 1) {
            $match['isview'] = 1;
            $match['read_ymd'] = ['$lte' => $ymd];
        } elseif ($type == 2) {
            $match['pushtime_ymd'] = ['$lte' => $ymd];
        }else{
            throw new FailedException("传入的类型参数错误");
        }

        $pip = [['$match' => $match], ['$group' => ['_id' => '$patientId']], ['$count' => 'peopleNum']];
        $ret = (new PEHModel())->mongoAggregate($pip);
        return $ret[0]['peopleNum']??0;
    }

    /**
     * 计算宣教人数
     * @param int $type 类型 1阅读人数，2推送人数
     * @param array $history_ids 宣教记录id
     * @param array $ymd 时间
     * @return array
     */
    private function calculateEdPeople(int $type, array $history_ids, array $ymd): array
    {
        //总人数
        $totalNum = $this->aggregationEvangelist($type, $history_ids, $ymd[1]);
        //开始日期之前人数
        $beforeNum = $this->aggregationEvangelist($type, $history_ids, $ymd[0]);

        //新增人数
        $newNum = 0;
        if ($beforeNum != 0) {
            $newNum = $totalNum - $beforeNum;
        }

        return [
            'totalNum' => $totalNum,
            'newNum' => $newNum
        ];
    }

    /**
     * 计算宣教量
     * @param array $where 条件
     * @param string $field 字段
     * @param array $ymd 时间
     * @return array
     */
    private function calculateEdMeasure(array $where, string $field, array $ymd): array
    {
        //总量
        $where1 = $where;
        $where1[] = [$field, '<=', $ymd[1]];
        $totalNum = (new PEHModel())->where($where1)->count();

        //开始日期之前量
        $where2 = $where;
        $where2[] = [$field, '<=', $ymd[0]];
        $beforeNum = (new PEHModel())->where($where2)->count();

        //新增量
        $newNum = 0;
        if ($beforeNum != 0) {
            $newNum = $totalNum - $beforeNum;
        }

        return [
            'totalNum' => $totalNum,
            'newNum' => $newNum
        ];
    }

    /**
     * 计算宣教推送课程数
     * @param array $history_ids 宣教记录id
     * @param array $ymd 时间
     * @return array
     */
    private function calculateEdPushCourse(array $history_ids, array $ymd): array
    {
        if (empty($ymd)) {
            throw new FailedException('请传入时间参数');
        }
        $where['deleted_at'] = 0;
        $where['_id'] = ['$in' => $history_ids];

        //总数
        $match1 = $where;
        $match1['pushtime_ymd'] = ['$lte' => $ymd[1]];
        $totalPip = [['$match' => $match1], ['$group' => ['_id' => ['ed_id' => '$ed_id']]], ['$count' => 'ed_push_num']];
        $total = (new PEHModel())->mongoAggregate($totalPip);
        $totalNum = $total[0]['ed_push_num']??0;

        //开始时间之前的数
        $match2 = $where;
        $match2['pushtime_ymd'] = ['$lte' => $ymd[0]];
        $beforePip = [['$match' => $match2], ['$group' => ['_id' => ['ed_id' => '$ed_id']]], ['$count' => 'ed_push_num']];
        $before = (new PEHModel())->mongoAggregate($beforePip);
        $beforeNum = $before[0]['ed_push_num']??0;

        //新增数
        $newNum = 0;
        if ($beforeNum != 0) {
            $newNum = $totalNum - $beforeNum;
        }

        return [
            'totalNum' => $totalNum,
            'newNum' => $newNum
        ];
    }

    /**
     * 计算宣教课程数
     * @param array $where 条件
     * @param array $ymd 时间
     * @return array
     */
    private function calculateEdCourse(array $where, array $ymd): array
    {
        //总数
        $where1 = $where;
        $where1[] = ['created_ymd', '<=', $ymd[1]];
        $totalNum = (new EDModel())->where($where1)->count();

        //开始日期之前数
        $where2 = $where;
        $where2[] = ['created_ymd', '<=', $ymd[0]];
        $beforeNum = (new EDModel())->where($where2)->count();

        //新增数
        $newNum = 0;
        if ($beforeNum != 0) {
            $newNum = $totalNum - $beforeNum;
        }

        return [
            'totalNum' => $totalNum,
            'newNum' => $newNum
        ];
    }

    /**
     * 数据详情
     * @param int $type 类型 1 按科室统计，2 按医护人员统计
     * @param int $department_id 科室id
     * @param array $pushTime 推送时间 [起-止]
     * @return array
     */
    public function getDataDetails(int $type=1, int $department_id=0, array $pushTime=[]): array
    {
        //定义查询条件
        $where = [];
        if ($department_id !== 0) {
            $where[] = ['department_id', '=', $department_id];
        }
        if (!empty($pushTime)) {
            $where[] = ['pushtime_ymd', '>=', $pushTime[0]];
            $where[] = ['pushtime_ymd', '<=', $pushTime[1]];
        }
        //查询条件匹配的宣教记录id
        $history_id = (new PEHModel())->where($where)->column('id');

        //将宣教记录id转换ObjectId类型
        $history_ids = array_map(function ($v) { return new ObjectId($v); }, $history_id);

        //匹配_id条件
        $match['_id'] = ['$in' => $history_ids];
        $match['deleted_at'] = 0;

        //判断类型，按类型返回数据
        if ($type == 1) {
            $pip = [['$match' => $match], ['$group' => ['_id' => ['department_id' => '$department_id'], 'department_name' => ['$first' => '$department_name'], 'patient_num' => ['$addToSet' => '$patientId'], 'reading_volume' => ['$sum' => ['$cond' => ['if' => ['$and' => [['$eq' => ['$isview', 1]]]], 'then' => 1, 'else' => 0]]], 'push_num' => ['$sum' => 1], 'reading_num' => ['$addToSet' => ['$cond' => ['if' => ['$eq' => ['$isview', 1]], 'then' => '$patientId', 'else' => '$$REMOVE']]]]], ['$project' => ['_id' => 0, 'department_name' => '$department_name', 'patient_num' => ['$size' => '$patient_num'], 'reading_volume' => '$reading_volume', 'push_num' => '$push_num', 'reading_people_num' => ['$size' => '$reading_num'], 'read_rate' => ['$concat' => [['$toString' => ['$multiply' => [['$round' => [['$divide' => ['$reading_volume', '$push_num']], 2]], 100]]], '%']], 'per_capita_push_num' => ['$round' => [['$divide' => ['$push_num', ['$size' => '$patient_num']]], 2]], 'avg_read_per_patient' => ['$round' => [['$divide' => ['$reading_volume', ['$size' => '$patient_num']]], 2]]]]];
        } elseif ($type == 2) {
            $pip = [['$match' => $match], ['$group' => ['_id' => ['creator_id' => '$creator_id'], 'reading_volume' => ['$sum' => ['$cond' => ['if' => ['$and' => [['$eq' => ['$isview', 1]]]], 'then' => 1, 'else' => 0]]], 'creator_name' => ['$first' => '$creator_name'], 'department_name' => ['$first' => '$department_name'], 'patient_num' => ['$addToSet' => '$patientId'], 'push_num' => ['$sum' => 1]]], ['$project' => ['_id' => 0, 'creator_name' => '$creator_name', 'department_name' => '$department_name', 'patient_num' => ['$size' => '$patient_num'], 'push_num' => '$push_num', 'reading_volume' => '$reading_volume', 'read_rate' => ['$concat' => [['$toString' => ['$multiply' => [['$round' => [['$divide' => ['$reading_volume', '$push_num']], 2]], 100]]], '%']], 'per_capita_push_num' => ['$round' => [['$divide' => ['$push_num', ['$size' => '$patient_num']]], 2]], 'avg_read_per_patient' => ['$round' => [['$divide' => ['$reading_volume', ['$size' => '$patient_num']]], 2]]]]];
        } else {
            throw new FailedException("传入的类型参数错误");
        }
        return (new PEHModel())->mongoAggregate($pip);
    }

    /**
     * 数据分析-排行榜
     * @param int $type 类型 1新增阅读人数，2新增阅读量，3新增推送课程数，新增推送人数
     * @param int $department_id 科室id
     * @param array $pushTime 推送时间 [起-止]
     * @param int $around 排名 1前五名，2后五名
     * @return array
     */
    public function getDataRanking(int $type=1,int $department_id=0, array $pushTime=[], int $around=0): array
    {
        //默认时间字段
        $ymd = 'pushtime_ymd';
        //默认排序字段
        $sort = 'reading_people_num';
        //默认排序倒序,如果传入后五名排序为正序
        $order = $around == 2?1:-1;

        //根据类型匹配查询条件
        switch ($type){
            case 1:
                $ymd = 'read_ymd';
                break;
            case 2:
                $ymd  = 'read_ymd';
                $sort = 'reading_volume';
                break;
            case 3:
                $sort = 'push_volume';
                break;
            case 4:
                $sort = 'push_patient_num';
                break;
        }

        //定义查询条件
        $where = [];
        if ($department_id !== 0) {
            $where[] = ['department_id', '=', $department_id];
        }
        if (!empty($pushTime)) {
            $where[] = [$ymd, '>=', $pushTime[0]];
            $where[] = [$ymd, '<=', $pushTime[1]];
        }
        //查询条件匹配的宣教记录id
        $history_id = (new PEHModel())->where($where)->column('id');

        //将宣教记录id转换ObjectId类型
        $history_ids = array_map(function ($v) { return new ObjectId($v); }, $history_id);

        //匹配_id条件
        $match['_id'] = ['$in' => $history_ids];
        $match['deleted_at'] = 0;

        $pip = [['$match' => $match], ['$group' => ['_id' => ['department_id' => '$department_id'], 'department_name' => ['$first' => '$department_name'], 'reading_people_num' => ['$addToSet' => ['$cond' => ['if' => ['$eq' => ['$isview', 1]], 'then' => '$patientId', 'else' => '$$REMOVE']]], 'reading_volume' => ['$sum' => ['$cond' => ['if' => ['$and' => [['$eq' => ['$isview', 1]]]], 'then' => 1, 'else' => 0]]], 'push_patient_num' => ['$addToSet' => '$patientId'], 'push_volume' => ['$sum' => 1]]], ['$project' => ['_id' => 0, 'department_name' => '$department_name', 'reading_people_num' => ['$size' => '$reading_people_num'], 'reading_volume' => '$reading_volume', 'push_patient_num' => ['$size' => '$push_patient_num'], 'push_volume' => '$push_volume']], ['$sort' => [$sort => $order]]];
        $data = (new PEHModel())->mongoAggregate($pip);

        //重组结果，加入排名名次
        $ret = [];
        foreach ($data as $k => $v) {
            $ret[] = [
                'ranking' => $k + 1,//名次
                'department_name' => $v['department_name']
            ];
        }

        //如果传入前五名或后五名，只返回五条数据
        if (in_array($around, [1,2])) {
            $ret = array_slice($ret, 0, 5);
        }
        return $ret;
    }

    /**
     * 数据分析-折线图
     * @param int $department_id 科室id
     * @param array $pushTime 时间
     * @return array
     */
    public function getDataChart(int $department_id=0, array $pushTime=[]): array
    {
        //定义查询条件
        $where = [];
        if ($department_id !== 0) {
            $where[] = ['department_id', '=', $department_id];
        }
        if (!empty($pushTime)) {
            $where[] = ['pushtime_ymd', '>=', $pushTime[0]];
            $where[] = ['pushtime_ymd', '<=', $pushTime[1]];
        }
        //查询条件匹配的宣教记录id
        $history_id = (new PEHModel())->where($where)->column('id');

        //将宣教记录id转换ObjectId类型
        $history_ids = array_map(function ($v) { return new ObjectId($v); }, $history_id);

        //匹配_id条件
        $match['_id'] = ['$in' => $history_ids];
        $match['deleted_at'] = 0;

        $pip = [['$match' => $match], ['$group' => ['_id' => ['pushtime_ymd' => '$pushtime_ymd'], 'push_volume' => ['$sum' => 1], 'reading_volume' => ['$sum' => ['$cond' => ['if' => ['$and' => [['$eq' => ['$isview', 1]]]], 'then' => 1, 'else' => 0]]], 'patient_num' => ['$addToSet' => '$patientId'], 'reading_num' => ['$addToSet' => ['$cond' => ['if' => ['$eq' => ['$isview', 1]], 'then' => '$patientId', 'else' => '$$REMOVE']]]]], ['$project' => ['_id' => 0, 'pushtime_ymd' => '$_id.pushtime_ymd', 'push_volume' => '$push_volume', 'reading_volume' => '$reading_volume', 'patient_num' => ['$size' => '$patient_num'], 'reading_people_num' => ['$size' => '$reading_num'], 'total' => ['$sum' => ['$push_volume', '$reading_volume', ['$size' => '$patient_num'], ['$size' => '$reading_num']]]]],['$sort' => ['pushtime_ymd' => 1]]];
        $data = (new PEHModel())->mongoAggregate($pip);

        $ret = [];
        foreach ($data as $k => $v) {
            $ret[$k]['date'] = $v['pushtime_ymd'];
            $ret[$k]['total'] = $v['total'];
            $ret[$k]['details'] = [
                'push_volume' => $v['push_volume'],
                'reading_volume' => $v['reading_volume'],
                'patient_num' => $v['patient_num'],
                'reading_people_num' => $v['reading_people_num']
            ];
        }
        return $ret;
    }
}